<?php

namespace App\Models\User\Repositories;

use App\Facades\User\UserCacheFacade;
use App\Models\User\Repositories\Interfaces\WechatMiniAppUserRepositoryInterface;
use App\Models\User\Repositories\Interfaces\WechatOfficialUserRepositoryInterface;
use App\Models\User\User;
use App\Models\User\WechatMiniAppUser;
use App\Models\User\WechatOfficialUser;
use App\Trip\Repository\BaseRepository;
use App\Trip\Tencent\Cloud\SDK\COS\Cos;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class UserRepository extends BaseRepository implements Interfaces\UserRepositoryInterface
{


    public function __construct(User $model)
    {
        parent::__construct($model);
    }

    public function addUser(array $data): User
    {

        $main_update_data = [];
        $phone            = $data['phone'] ?? ($data['mobile'] ?? '');
        $nickname         = $data['nickname'] ?? '';
        $avatar           = $data['avatar'] ?? '';
        if ($user = $this->getUserByUnionIdOpenIdType($data['unionid'], $data['openid'], $data['client_type'])) {
            if (!$user->getPhone() && $phone && ($user->getPhone() != $phone)) {
                $main_update_data['phone'] = $phone;
            }

            if ($nickname && ($user->getNickName() != $nickname)) {
                $main_update_data['nickname'] = $nickname;
            }
            // 这里默认保存 原始  后面要处理
            if (!$user->getAvatar() && $avatar) {
                $main_update_data['avatar'] = $avatar;
            }

            $main_update_data && $this->updateUser($user, $main_update_data);
            if (!$this->getMiniAppUserByOpenId($user, $data['openid'])) {
                $this->addMiniUser($user, $data);
            }
            return $user;
        }
        // 第一步 先添加 开放平台
        DB::transaction(function () use (&$user, $data, $phone) {
            // 如果小程序用户已存在 直接更新unionid
            $miniRepo = app(WechatMiniAppUserRepositoryInterface::class);
            if ($miniUserInfo = $miniRepo->findByOpenId($data['openid'])) {
                $user = $this->getUserByUserId($miniUserInfo->getUserId());
                $this->updateUser($user, [
                    'unionid' => $data['unionid'],
                ]);
            } else {
                $user = $this->create($data);
                $this->addMiniUser($user, $data);
            }
        });
        return $user;
    }

    public function getUserByUnionIdOpenIdType(string $union_id, string $open_id, int $client_type): User|null
    {
        $cache_key = "User:u:{$union_id}:o:{$open_id}:t:{$client_type}";
        if (Cache::has($cache_key)) {
            $user = Cache::get($cache_key);
            UserCacheFacade::cache($user);
            return $user;
        }
        /**
         * @var  User $user
         */
        $user = $this->findOneBy(['unionid' => $union_id]);
        if ($user && $client_type == User::CLIENT_TYPE_WECHAT_MINIAPP) {
            $miniRepo     = app(WechatMiniAppUserRepositoryInterface::class);
            $miniUserInfo = $miniRepo->findByOpenId($open_id);
            if ($miniUserInfo && $miniUserInfo->getUserId() != $user->getUserId()) {
                $this->updateUser($user, [
                    'unionid' => $union_id,
                ]);
            }
        }

        if ($user && $client_type == User::CLIENT_TYPE_WECHAT_OFFICIAL) {
            $officialRepo     = app(WechatOfficialUserRepositoryInterface::class);
            $officialUserInfo = $officialRepo->findByOpenId($open_id);
            if ($officialUserInfo && $officialUserInfo->getUserId() != $user->getUserId()) {
                $this->updateUser($user, [
                    'unionid' => $union_id,
                ]);
            }
        }
        $user
        && Cache::put($cache_key, $user, config('trip.ttl.day'))
        && UserCacheFacade::cache($user);
        return $user;
    }

    public function updateUser(User $user, array $param): bool
    {
        if (empty($param)) {
            return true;
        }
        return $this->update($param, $user);
    }

    public function getMiniAppUserByOpenId(User $user, string $openid): ?WechatMiniAppUser
    {
        $appUserRepo = new WechatMiniAppUserRepository(new WechatMiniAppUser());
        $appUser     = $appUserRepo->findByOpenId($openid);
        if ($appUser && $appUser->getUserId() != $user->getUserId()) {
            Log::error("getAppUserByOpenId:ERROR:{$appUser->getUserId()} {$user->getUserId()}");
        }
        return $appUser;
    }

    public function addMiniUser(User $user, array $data): WechatMiniAppUser
    {
        $miniRepo = app(WechatMiniAppUserRepositoryInterface::class);
        return $miniRepo->addData([
            'user_id' => $user->getUserId(),
            'openid'  => $data['openid'],
            'appid'   => $data['appid'],
        ]);
    }

    public function getUserByUserId(string $user_id): ?User
    {
        $cache_key = "User:userInfo:{$user_id}";
        if (Cache::has($cache_key)) {
            return Cache::get($cache_key);
        }
        $user = $this->findOneBy(['user_id' => $user_id]);
        $user && Cache::put($cache_key, $user, config('trip.ttl.day'));
        return $user;
    }

    public function getMiniAppUserByAppId(User $user, string $appid): ?WechatMiniAppUser
    {
        $appUserRepo = new WechatMiniAppUserRepository(new WechatMiniAppUser());
        return $appUserRepo->findByAppIdAndUserId($user->getUserId(), $appid);
    }

    public function getOfficialUserByOpenId(User $user, string $openid): ?WechatOfficialUser
    {
        $appUserRepo = new WechatOfficialUserRepository(new WechatOfficialUser());
        $appUser     = $appUserRepo->findByOpenId($openid);
        if ($appUser && $appUser->getUserId() != $user->getUserId()) {
            Log::error("getAppUserByOpenId:ERROR:{$appUser->getUserId()} {$user->getUserId()}");
        }
        return $appUser;
    }

    public function getOfficialUserByAppId(User $user, string $appid): ?WechatOfficialUser
    {
        $appUserRepo = new WechatOfficialUserRepository(new WechatOfficialUser());
        return $appUserRepo->findByAppIdAndUserId($user->getUserId(), $appid);
    }

    /**
     * @throws GuzzleException
     * @throws Exception
     */
    public function updateUserAvatar(User $user): bool
    {
        if (!$user->getAvatar()) {
            return false;
        }

        $ac = "User:{$user->getUnionId()}:Avatar";
        if (!Str::contains($user->getAvatar(), 'trip-dove')) {
            $client         = new Client;
            $avatarResponse = $client->get($user->getAvatar());
            $avatar         = $avatarResponse->getBody()->getContents();
            $fileName       = 'avatar.jpg';
            $key            = md5($user->getUnionId());
            $pathName       = "User/{$key}/Avatar/{$fileName}";
            $cos            = new Cos();
            $url            = $cos->uploadRemoteImage($avatar, $pathName);
            if ($url) {
                $this->updateUser($user, [
                    'avatar' => $url,
                ]);
                Cache::put($ac, $url, config('trip.ttl.day') * 15);
            }
        }
        return true;
    }

    public function addOfficialUser(User $user, array $data): WechatOfficialUser
    {
        $repo = app(WechatOfficialUserRepositoryInterface::class);
        return $repo->addData([
            'user_id' => $user->getUserId(),
            'openid'  => $data['openid'],
            'appid'   => $data['appid'],
        ]);
    }


}